English
English
Appearance
English
English
Appearance
A step-by-step guide to connecting social media accounts to your Repliz workspace using the OAuth API.
Most platforms start the same way: you request an authorization URL, the user approves access in their browser, and the platform redirects back to your app with an authorization code. What you do with that code depends on the platform.
code straight to Connect.code for a token, list the available assets, and then connect the one the user picks.WhatsApp and Telegram have no authorization page or redirect. They use a third flow:
Access Tier
The OAuth API is available on the Gold+ tier. All requests use Basic Auth (Authorization: Basic Base64(AccessKey:SecretKey)).
| Platform | Flow | Asset to pick | Asset list endpoint | ID field on Connect |
|---|---|---|---|---|
| Direct | - | - | - | |
| Threads | Direct | - | - | - |
| TikTok | Direct | - | - | - |
| Shopee | Direct | - | - | - |
| X (Twitter) | Direct | - | - | - |
| Direct | - | - | - | |
| With asset selection | Page | Get Page Facebook | pageId | |
| YouTube | With asset selection | Channel | Get Channel YouTube | channelId |
| With asset selection | Personal account or organization | Get Organization LinkedIn | organizationId | |
| QR code | - | - | - | |
| Telegram | QR code | - | - | - |
All endpoints follow the same path pattern, where {platform} is one of facebook, instagram, threads, youtube, linkedin, tiktok, shopee, twitter, pinterest, whatsapp, or telegram:
| Step | Endpoint | Platforms |
|---|---|---|
| Authorize | GET /public/account/{platform}/authorize | All except WhatsApp and Telegram |
| Exchange | POST /public/account/{platform}/exchange | Facebook, YouTube, LinkedIn |
| Create session | POST /public/account/{platform}/session | WhatsApp, Telegram |
| Get session | GET /public/account/{platform}/session | WhatsApp, Telegram |
| Send password | POST /public/account/telegram/session/password | Telegram |
| List asset | GET /public/account/facebook/page | |
| List asset | GET /public/account/youtube/channel | YouTube |
| List asset | GET /public/account/linkedin/organization | |
| Connect | POST /public/account/{platform}/connect | All |
| Reconnect | POST /public/account/{platform}/connect/{accountId} | All |
Used by Instagram, Threads, TikTok, Shopee, X (Twitter), and Pinterest.
Authorize → User approves → Redirect with code → Connect / ReconnectCall Authorize with the redirect URL where the user should land after approving access. URL-encode the value if it contains its own query string.
curl -X GET "https://api.repliz.com/public/account/tiktok/authorize?redirect=https://your-app.com/oauth/callback" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)"{
"url": "https://www.tiktok.com/v2/auth/authorize?client_key=...&redirect_uri=https://your-app.com/oauth/callback&state=..."
}Open the returned url in the user's browser, either as a full-page redirect or a popup. The user logs in and approves access on the platform's own page, so this step cannot run on your server alone.
After the user approves, the platform sends them back to your redirect URL. On most platforms the authorization code is in the query string:
https://your-app.com/oauth/callback?code=AUTH_CODE_FROM_REDIRECT&state=...Read the code parameter on your callback page and pass it to your backend. You don't need to send state to Repliz.
Two platforms return the value in a different shape:
| Platform | What the redirect contains | Send as code |
|---|---|---|
#access_token=... in the URL fragment | The access_token value | |
| Shopee | ?code=...&shop_id=... in the query string | Both joined with an underscore: {code}_{shop_id} |
| Others | ?code=... in the query string | The code value |
The URL fragment (everything after #) never reaches your server, so for Facebook read it in the browser with window.location.hash and pass the value to your backend.
Use the code right away
Authorization codes are short-lived and can only be used once. If Connect fails because the code has expired or was already used, start again from Step 1.
Send the code to Connect. Repliz exchanges it with the platform and adds the account to your workspace.
curl -X POST "https://api.repliz.com/public/account/tiktok/connect" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"code":"AUTH_CODE_FROM_REDIRECT"}'{
"accountId": "69e97477a795504e0786cec6"
}Store the accountId. You will use it for schedules, automations, and any later reconnect.
To reconnect an existing account instead, send the same body to the Reconnect endpoint with the accountId in the path. It returns 204 No Content on success.
curl -X POST "https://api.repliz.com/public/account/tiktok/connect/69e97477a795504e0786cec6" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"code":"AUTH_CODE_FROM_REDIRECT"}'Pinterest uses the direct flow with pinterest in the path. The account you connect is the Pinterest user who approves access, not one of their boards. Boards are picked per post instead:
accountId to list the boards.additionalInfo.channel in Create Schedule, and optionally the pin's destination URL as additionalInfo.link.{
"title": "Smart Comment Management",
"description": "Hola from Repliz!",
"type": "image",
"medias": [{ "type": "image", "url": "https://storage.repliz.com/image.png", "thumbnail": "", "alt": "Repliz dashboard" }],
"additionalInfo": {
"channel": {
"id": "1006921296753698211",
"name": "Social Media Tips",
"picture": "https://i.pinimg.com/400x300/fd/cd/d5/fdcdd5a6d8a80824add0d054125cd957.jpg",
"type": "board"
},
"link": "https://repliz.com"
},
"accountId": "69e97477a795504e0786cec6",
"scheduleAt": "2026-10-10T09:00:00.000Z"
}Each schedule goes to one board, so create one schedule per board.
Used by Facebook, YouTube, and LinkedIn. One login on these platforms can manage several assets: a Facebook user can manage many Pages, a Google account can own several YouTube channels, and a LinkedIn member can connect their personal account or any organization they administer. Each Repliz account maps to one asset, so the user has to pick which one to connect.
Authorize → User approves → Redirect with code → Exchange → Get Page / Channel / Organization → Connect / ReconnectThese are the same as in the Direct Flow. Call the platform's Authorize endpoint, open the returned url in the browser, and read the value from your callback URL. For Facebook, that value is the access_token in the URL fragment; see Step 2.
curl -X GET "https://api.repliz.com/public/account/facebook/authorize?redirect=https://your-app.com/oauth/callback" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)"Send the code to Exchange. Unlike the direct flow, this does not connect anything yet. It returns a token that lets you list the user's assets.
curl -X POST "https://api.repliz.com/public/account/facebook/exchange" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"code":"AUTH_CODE_FROM_REDIRECT"}'{
"token": "9402c20336a7c3ce2d8e4f76...2255a73f-8431-4458-abcf-ee7f867952db"
}Pass the token from Step 3 as a query parameter to the platform's list endpoint:
| Platform | Endpoint |
|---|---|
GET /public/account/facebook/page | |
| YouTube | GET /public/account/youtube/channel |
GET /public/account/linkedin/organization |
curl -X GET "https://api.repliz.com/public/account/facebook/page?token=TOKEN_FROM_EXCHANGE" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)"All three endpoints return the same shape:
{
"docs": [
{
"id": "113958387982006",
"name": "Halaman ke 3",
"username": "Kafe",
"picture": "https://scontent.fbdo9-1.fna.fbcdn.net/v/t39.30808-1/...",
"token": "PAGE_ACCESS_TOKEN"
}
]
}| Field | Description |
|---|---|
id | The ID of the Page, channel, or LinkedIn account. Send it to Connect. |
name | Display name, useful for showing a picker to the user. |
username | Handle or username of the asset. |
picture | Avatar URL of the asset. |
token | Access token tied to this asset. Send it to Connect. |
LinkedIn personal accounts
For LinkedIn, the list includes the user's own personal account (urn:li:person:...) along with the organizations they administer (urn:li:organization:...). Both are connected the same way, by sending the id as organizationId.
Show the list to the user and let them choose which asset to connect. If docs is empty, the account the user logged in with doesn't manage any Page, channel, or organization.
Send the chosen item's id and token to Connect. The name of the ID field depends on the platform:
| Platform | Request body |
|---|---|
{ "pageId": "...", "token": "..." } | |
| YouTube | { "channelId": "...", "token": "..." } |
{ "organizationId": "...", "token": "..." } |
curl -X POST "https://api.repliz.com/public/account/facebook/connect" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"pageId":"113958387982006","token":"PAGE_ACCESS_TOKEN"}'{
"accountId": "680affa5ce12f2f72916f67e"
}To connect several assets, call Connect once for each selected item. Each call creates a separate account with its own accountId.
To reconnect an existing account, send the same body to the Reconnect endpoint with the accountId in the path. Pick the same Page, channel, or LinkedIn account the account was originally connected with. It returns 204 No Content on success.
curl -X POST "https://api.repliz.com/public/account/facebook/connect/680affa5ce12f2f72916f67e" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"pageId":"113958387982006","token":"PAGE_ACCESS_TOKEN"}'Here is the complete flow for the direct and asset selection types in JavaScript. For WhatsApp, see the QR code flow example, and for Telegram, the Telegram example. getAuthorizeUrl runs before the redirect; handleCallback runs on your callback URL with the code from the query string.
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.repliz.com/public/account',
auth: {
username: 'YOUR_ACCESS_KEY',
password: 'YOUR_SECRET_KEY',
},
});
// Platforms that need an asset picked after login, with their list endpoint and ID field
const ASSET_PLATFORMS = {
facebook: { list: 'page', idField: 'pageId' },
youtube: { list: 'channel', idField: 'channelId' },
linkedin: { list: 'organization', idField: 'organizationId' },
};
// Read the value to send as `code` from your callback URL
function getCode(platform, callbackUrl) {
const url = new URL(callbackUrl);
// Facebook returns an access token in the URL fragment
if (platform === 'facebook') {
return new URLSearchParams(url.hash.slice(1)).get('access_token');
}
const code = url.searchParams.get('code');
// Shopee needs the shop ID joined to the code
if (platform === 'shopee') {
return `${code}_${url.searchParams.get('shop_id')}`;
}
return code;
}
// Step 1: Get the authorization URL and send the user to it
async function getAuthorizeUrl(platform, redirect) {
const { data } = await api.get(`/${platform}/authorize`, {
params: { redirect },
});
return data.url;
}
// Step 2+: Called on your callback page with the code from the redirect.
// Pass accountId to reconnect an existing account instead of adding a new one.
async function handleCallback(platform, code, accountId, pickAsset) {
const connectPath = accountId
? `/${platform}/connect/${accountId}`
: `/${platform}/connect`;
const asset = ASSET_PLATFORMS[platform];
// Direct flow: Instagram, Threads, TikTok, Shopee, X
if (!asset) {
const { data } = await api.post(connectPath, { code });
return data;
}
// Asset selection flow: Facebook, YouTube, LinkedIn
const { data: exchange } = await api.post(`/${platform}/exchange`, { code });
const { data: list } = await api.get(`/${platform}/${asset.list}`, {
params: { token: exchange.token },
});
const selected = await pickAsset(list.docs); // let the user choose one
const { data } = await api.post(connectPath, {
[asset.idField]: selected.id,
token: selected.token,
});
return data;
}
// Usage
const url = await getAuthorizeUrl('facebook', 'https://your-app.com/oauth/callback');
// ...user approves and lands on your callback URL, where you read the code
const code = getCode('facebook', window.location.href);
const result = await handleCallback('facebook', code, null, (docs) => docs[0]);
console.log('Connected account:', result.accountId);const API_BASE = 'https://api.repliz.com/public/account';
const credentials = btoa('YOUR_ACCESS_KEY:YOUR_SECRET_KEY');
// Platforms that need an asset picked after login, with their list endpoint and ID field
const ASSET_PLATFORMS = {
facebook: { list: 'page', idField: 'pageId' },
youtube: { list: 'channel', idField: 'channelId' },
linkedin: { list: 'organization', idField: 'organizationId' },
};
// Read the value to send as `code` from your callback URL
function getCode(platform, callbackUrl) {
const url = new URL(callbackUrl);
// Facebook returns an access token in the URL fragment
if (platform === 'facebook') {
return new URLSearchParams(url.hash.slice(1)).get('access_token');
}
const code = url.searchParams.get('code');
// Shopee needs the shop ID joined to the code
if (platform === 'shopee') {
return `${code}_${url.searchParams.get('shop_id')}`;
}
return code;
}
async function request(path, { method = 'GET', body } = {}) {
const response = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Basic ${credentials}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
return response.status === 204 ? null : response.json();
}
// Step 1: Get the authorization URL and send the user to it
async function getAuthorizeUrl(platform, redirect) {
const data = await request(
`/${platform}/authorize?redirect=${encodeURIComponent(redirect)}`,
);
return data.url;
}
// Step 2+: Called on your callback page with the code from the redirect.
// Pass accountId to reconnect an existing account instead of adding a new one.
async function handleCallback(platform, code, accountId, pickAsset) {
const connectPath = accountId
? `/${platform}/connect/${accountId}`
: `/${platform}/connect`;
const asset = ASSET_PLATFORMS[platform];
// Direct flow: Instagram, Threads, TikTok, Shopee, X
if (!asset) {
return request(connectPath, { method: 'POST', body: { code } });
}
// Asset selection flow: Facebook, YouTube, LinkedIn
const exchange = await request(`/${platform}/exchange`, {
method: 'POST',
body: { code },
});
const list = await request(
`/${platform}/${asset.list}?token=${encodeURIComponent(exchange.token)}`,
);
const selected = await pickAsset(list.docs); // let the user choose one
return request(connectPath, {
method: 'POST',
body: { [asset.idField]: selected.id, token: selected.token },
});
}
// Usage
const url = await getAuthorizeUrl('facebook', 'https://your-app.com/oauth/callback');
// ...user approves and lands on your callback URL, where you read the code
const code = getCode('facebook', window.location.href);
const result = await handleCallback('facebook', code, null, (docs) => docs[0]);
console.log('Connected account:', result.accountId);Used by WhatsApp and Telegram. There is no consent page to redirect to. Instead, Repliz links itself to the user's account as a device, the same way WhatsApp Web or Telegram Desktop does: you show a QR code and the user scans it from their phone. The scan connects that WhatsApp number or Telegram account as one Repliz account.
The steps below use WhatsApp. Telegram follows them with telegram in the path, plus a password step for accounts with Two-Step Verification.
Create Session → Poll Get Session and show the QR code → User scans → Connect / ReconnectCall Create Session. It returns a session token that the other WhatsApp calls take.
curl -X POST "https://api.repliz.com/public/account/whatsapp/session" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)"{
"token": "a2ee814b0a49d6a55d07a73db97578387e1cb226...8bf0181672039791e2b92e1e77347c86fc5cab9f8051a3a8ebbdde7db3dee9"
}Call Get Session with the token every 2 seconds.
curl -X GET "https://api.repliz.com/public/account/whatsapp/session?token=SESSION_TOKEN" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)"{
"id": "6a38d93d824af0f1182e7486",
"generatedId": "",
"name": "",
"sessionId": "533e6fca-8c88-48c0-86c2-438d43fbc986",
"isConnected": false,
"qrcode": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAABlBMVEX///8AAABVwtN+AAAE...",
"picture": ""
}While isConnected is false, show qrcode as an image by prefixing it with data:image/png;base64,. Ask the user to open WhatsApp on their phone, tap Linked devices (in the ⋮ menu on Android, or in Settings on iPhone), then Link a device, and scan the code.
qrcode can be empty for a moment right after the session is created. Keep polling until it appears.isConnected is true. qrcode is empty again and name, picture, and generatedId now describe the number that scanned. Continue to Step 3.404 session not found means the code expired before anyone scanned it. Go back to Step 1 for a new session. Also stop polling after about 4 minutes, so a page the user abandoned doesn't poll forever.Send the token to Connect:
curl -X POST "https://api.repliz.com/public/account/whatsapp/connect" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"token":"SESSION_TOKEN"}'{
"accountId": "69e97477a795504e0786cec6"
}Connecting a number that is already in your workspace updates that account instead of adding a duplicate. Connect returns 403 invalid status session if the QR code hasn't been scanned yet.
To reconnect an account, run Steps 1 and 2 again so the user scans a new QR code, then send the new token to the Reconnect endpoint with the accountId in the path. It returns 204 No Content on success. The user has to scan with the number the account belongs to; any other number returns 400 incorrect generatedId to reconnect.
curl -X POST "https://api.repliz.com/public/account/whatsapp/connect/69e97477a795504e0786cec6" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"token":"NEW_SESSION_TOKEN"}'The WhatsApp Channels the number owns and the groups it has joined are not separate accounts. A schedule for the WhatsApp account goes to the number's Status unless it names a Channel or group:
accountId to list the Channels and groups.additionalInfo.channel in Create Schedule.{
"title": "",
"description": "Hola from Repliz!",
"type": "text",
"medias": [],
"additionalInfo": {
"channel": {
"id": "120363413774168194@newsletter",
"name": "Boom",
"picture": "https://pps.whatsapp.net/m1/v/t24/An-6sQyuS8Q9UAjgMTbC8PQ5J3fWqldErtluDIBugLBhJk7llbTd2XIQT...",
"type": "channel"
}
},
"accountId": "69e97477a795504e0786cec6",
"scheduleAt": "2026-10-10T09:00:00.000Z"
}Each schedule goes to one place, so create one schedule per Channel or group.
Telegram uses the same steps with telegram in the path instead of whatsapp, plus one extra step for accounts protected by Two-Step Verification.
Create a session with POST /public/account/telegram/session.
Poll Get Session (GET /public/account/telegram/session?token=...) and show qrcode. Ask the user to open Telegram on their phone, go to Settings → Devices, tap Link Desktop Device, and scan the code. Telegram replaces the code about every 30 seconds, and the session is deleted if nobody scans it within about three minutes.
Send the password if asked. After the scan, an account with Two-Step Verification returns isPasswordRequired: true and an empty qrcode. Ask the user for their password, showing passwordHint if it isn't empty, and send it to Password Session Telegram:
curl -X POST "https://api.repliz.com/public/account/telegram/session/password" \
-H "Authorization: Basic $(echo -n 'YOUR_ACCESS_KEY:YOUR_SECRET_KEY' | base64)" \
-H "Content-Type: application/json" \
-d '{"token":"SESSION_TOKEN","password":"USER_PASSWORD"}'It returns 204 No Content when Telegram accepts the password, and 400 invalid password when it doesn't, so the user can try again with the same session. Keep polling Get Session either way.
Connect with POST /public/account/telegram/connect once isConnected is true, or Reconnect with POST /public/account/telegram/connect/{accountId}. A different Telegram account returns 400 incorrect generatedId to reconnect.
A schedule for the Telegram account goes to its Story unless it names a channel or group. List them with Get Telegram Channel and pass the chosen item as additionalInfo.channel, including its type: Telegram channel and supergroup IDs look the same, so type decides whether the post goes to a channel or a group.
The connected account also brings its private chats into the Chat API, where the chat module of account automation can answer them.
waitForLogin covers the scan and the password. askPassword receives the hint and must resolve to the password the user typed.
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.repliz.com/public/account/telegram',
auth: {
username: 'YOUR_ACCESS_KEY',
password: 'YOUR_SECRET_KEY',
},
});
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Create a session and wait until the login is complete.
// Throws on 404 if the code expired; call it again to show a new one.
async function waitForLogin(showQRCode, askPassword, { interval = 2000, timeout = 4 * 60 * 1000 } = {}) {
const { data } = await api.post('/session');
let deadline = Date.now() + timeout;
let lastQRCode = '';
while (Date.now() < deadline) {
const { data: session } = await api.get('/session', {
params: { token: data.token },
});
if (session.isConnected) return data.token;
if (session.isPasswordRequired) {
const password = await askPassword(session.passwordHint);
try {
await api.post('/session/password', { token: data.token, password });
} catch (error) {
// A wrong password leaves isPasswordRequired on, so the next poll asks again
if (error.response?.status !== 400) throw error;
}
// Typing the password doesn't count against the scan timeout
deadline = Date.now() + timeout;
} else if (session.qrcode && session.qrcode !== lastQRCode) {
// The code changes about every 30 seconds, so redraw it whenever it does
lastQRCode = session.qrcode;
showQRCode(`data:image/png;base64,${session.qrcode}`);
}
await sleep(interval);
}
throw new Error('The QR code was not scanned in time');
}
async function connectTelegram(showQRCode, askPassword) {
const token = await waitForLogin(showQRCode, askPassword);
const { data } = await api.post('/connect', { token });
return data.accountId;
}
async function reconnectTelegram(accountId, showQRCode, askPassword) {
const token = await waitForLogin(showQRCode, askPassword);
await api.post(`/connect/${accountId}`, { token });
}
// Usage
const accountId = await connectTelegram(
(src) => {
document.querySelector('#telegram-qr').src = src;
},
async (hint) => window.prompt(hint ? `Telegram password (hint: ${hint})` : 'Telegram password'),
);
console.log('Connected account:', accountId);const API_BASE = 'https://api.repliz.com/public/account/telegram';
const credentials = btoa('YOUR_ACCESS_KEY:YOUR_SECRET_KEY');
async function request(path, { method = 'GET', body } = {}) {
const response = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Basic ${credentials}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
const error = new Error(`${response.status} ${await response.text()}`);
error.status = response.status;
throw error;
}
return response.status === 204 ? null : response.json();
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Create a session and wait until the login is complete.
// Throws on 404 if the code expired; call it again to show a new one.
async function waitForLogin(showQRCode, askPassword, { interval = 2000, timeout = 4 * 60 * 1000 } = {}) {
const { token } = await request('/session', { method: 'POST' });
let deadline = Date.now() + timeout;
let lastQRCode = '';
while (Date.now() < deadline) {
const session = await request(`/session?token=${encodeURIComponent(token)}`);
if (session.isConnected) return token;
if (session.isPasswordRequired) {
const password = await askPassword(session.passwordHint);
try {
await request('/session/password', { method: 'POST', body: { token, password } });
} catch (error) {
// A wrong password leaves isPasswordRequired on, so the next poll asks again
if (error.status !== 400) throw error;
}
// Typing the password doesn't count against the scan timeout
deadline = Date.now() + timeout;
} else if (session.qrcode && session.qrcode !== lastQRCode) {
// The code changes about every 30 seconds, so redraw it whenever it does
lastQRCode = session.qrcode;
showQRCode(`data:image/png;base64,${session.qrcode}`);
}
await sleep(interval);
}
throw new Error('The QR code was not scanned in time');
}
async function connectTelegram(showQRCode, askPassword) {
const token = await waitForLogin(showQRCode, askPassword);
const data = await request('/connect', { method: 'POST', body: { token } });
return data.accountId;
}
async function reconnectTelegram(accountId, showQRCode, askPassword) {
const token = await waitForLogin(showQRCode, askPassword);
await request(`/connect/${accountId}`, { method: 'POST', body: { token } });
}
// Usage
const accountId = await connectTelegram(
(src) => {
document.querySelector('#telegram-qr').src = src;
},
async (hint) => window.prompt(hint ? `Telegram password (hint: ${hint})` : 'Telegram password'),
);
console.log('Connected account:', accountId);waitForScan covers Steps 1 and 2 and calls showQRCode whenever the code changes. connectWhatsApp and reconnectWhatsApp build on it.
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.repliz.com/public/account/whatsapp',
auth: {
username: 'YOUR_ACCESS_KEY',
password: 'YOUR_SECRET_KEY',
},
});
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Steps 1 and 2: create a session and wait until the user scans its QR code.
// Throws on 404 if the code expired; call it again to show a new one.
async function waitForScan(showQRCode, { interval = 2000, timeout = 4 * 60 * 1000 } = {}) {
const { data } = await api.post('/session');
const deadline = Date.now() + timeout;
let lastQRCode = '';
while (Date.now() < deadline) {
const { data: session } = await api.get('/session', {
params: { token: data.token },
});
if (session.isConnected) return data.token;
// The code changes every 20 to 60 seconds, so redraw it whenever it does
if (session.qrcode && session.qrcode !== lastQRCode) {
lastQRCode = session.qrcode;
showQRCode(`data:image/png;base64,${session.qrcode}`);
}
await sleep(interval);
}
throw new Error('The QR code was not scanned in time');
}
// Step 3: connect the number that scanned the code
async function connectWhatsApp(showQRCode) {
const token = await waitForScan(showQRCode);
const { data } = await api.post('/connect', { token });
return data.accountId;
}
// Reconnect: same scan, then send the token with the existing accountId
async function reconnectWhatsApp(accountId, showQRCode) {
const token = await waitForScan(showQRCode);
await api.post(`/connect/${accountId}`, { token });
}
// Usage
const accountId = await connectWhatsApp((src) => {
document.querySelector('#whatsapp-qr').src = src;
});
console.log('Connected account:', accountId);const API_BASE = 'https://api.repliz.com/public/account/whatsapp';
const credentials = btoa('YOUR_ACCESS_KEY:YOUR_SECRET_KEY');
async function request(path, { method = 'GET', body } = {}) {
const response = await fetch(`${API_BASE}${path}`, {
method,
headers: {
Authorization: `Basic ${credentials}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
return response.status === 204 ? null : response.json();
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Steps 1 and 2: create a session and wait until the user scans its QR code.
// Throws on 404 if the code expired; call it again to show a new one.
async function waitForScan(showQRCode, { interval = 2000, timeout = 4 * 60 * 1000 } = {}) {
const { token } = await request('/session', { method: 'POST' });
const deadline = Date.now() + timeout;
let lastQRCode = '';
while (Date.now() < deadline) {
const session = await request(`/session?token=${encodeURIComponent(token)}`);
if (session.isConnected) return token;
// The code changes every 20 to 60 seconds, so redraw it whenever it does
if (session.qrcode && session.qrcode !== lastQRCode) {
lastQRCode = session.qrcode;
showQRCode(`data:image/png;base64,${session.qrcode}`);
}
await sleep(interval);
}
throw new Error('The QR code was not scanned in time');
}
// Step 3: connect the number that scanned the code
async function connectWhatsApp(showQRCode) {
const token = await waitForScan(showQRCode);
const data = await request('/connect', { method: 'POST', body: { token } });
return data.accountId;
}
// Reconnect: same scan, then send the token with the existing accountId
async function reconnectWhatsApp(accountId, showQRCode) {
const token = await waitForScan(showQRCode);
await request(`/connect/${accountId}`, { method: 'POST', body: { token } });
}
// Usage
const accountId = await connectWhatsApp((src) => {
document.querySelector('#whatsapp-qr').src = src;
});
console.log('Connected account:', accountId);| Use | When | Result |
|---|---|---|
| Connect | Adding an account that is not in your workspace yet. | 200 with a new accountId |
| Reconnect | An existing account lost access, for example the token expired or the user revoked the app. | 204 No Content, same accountId |
Reconnect keeps the same accountId, so schedules, automations, and anything else that references the account keep working. Use Get Account or Get One Account to check the isConnected field and find accounts that need a reconnect.
Both run the same flow for the platform. The only difference is the final request: Reconnect adds /{accountId} to the Connect path.
| Status | Message | Cause and fix |
|---|---|---|
400 | incorrect generatedId to reconnect | The account the user logged in with, or the asset they picked, is not the one linked to accountId. Log in with the same platform account and pick the same Page, channel, or LinkedIn account. For WhatsApp, scan the QR code with the number the account belongs to, and for Telegram, with the same Telegram account. |
404 | account not found | The accountId on Reconnect doesn't exist in your workspace. |
400 | invalid password | Telegram only. The Two-Step Verification password is wrong. Ask the user again and resend it with the same session token. |
403 | invalid status session | WhatsApp and Telegram only. The login isn't complete yet: the QR code hasn't been scanned, or on Telegram the password hasn't been sent. Keep polling Get Session until isConnected is true before calling Connect or Reconnect. |
404 | session not found | WhatsApp and Telegram only. The session expired because nobody scanned the QR code in time. Create a new session. |
402 | please upgrade plan to connect more account | Connect only. Your workspace has reached its plan's account limit. |
401 | unauthorized | Your Access Key or Secret Key is wrong. See Install. |
isConnected status